package com.langtags.gears;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;

public class IOUtils {

	public static Object readObject(InputStream is) throws IOException,
			ClassNotFoundException {
		ObjectInputStream ois = new ObjectInputStream(is);
		return ois.readObject();
	}

	public static void writeObject(Object obj, File file) {
		try {
			FileOutputStream fos = new FileOutputStream(file);
			ObjectOutputStream oos = new ObjectOutputStream(fos);
			oos.writeObject(obj);
			oos.close();
			fos.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void appendToJar(File src, File targetDir, Map gmapApi,
			Map<String, String> typeVar) throws IOException {
        File target = new File(targetDir,src.getName());		
		Map<String, Map<String, Map>> h2Map = gmapApi;
		Map<String, String> fcrecs = new HashMap<String, String>();
		Map startTypes = new HashMap();
		for (String h2 : h2Map.keySet()) {
			Map<String, Map> context = new HashMap<String, Map>();
			Map<String, Map> map = h2Map.get(h2);
			Map methods = map.get("methods");
			Map properties = map.get("properties");
			processMethodMap(methods,typeVar);
			preprocessMap(properties,typeVar);
				String var = typeVar.get(h2);
				String[] vs = split(var);
				if (methods != null) {
					context.put("methods", methods);
				}
				if (properties != null) {
					context.put("properties", properties);
				}
				for(String v:vs){
					startTypes.put(v, "gears" + v + "class");
					String filename = "gears" + v + "class.fcrec";
					String filecontent = FCRecTemplate.template(context);
					fcrecs.put(filename, filecontent);	
				}
				
		}
		
		
		Map<String, Map> startContext = new HashMap<String, Map>();
		startTypes.put("google", "gearsgoogleclass");
		
		startContext.put("startTypes", startTypes);
		
		String startapp = FCRecTemplate.startTemplate(startContext);

		Map<String, Map> context = new HashMap<String, Map>();
		Map properties = new HashMap();
		properties.put("gears", "gearsgearsclass");
		context.put("properties", properties);
		String fname = "gearsgoogleclass.fcrec";
		String fcontent = FCRecTemplate.template(context);
		fcrecs.put(fname, fcontent);
		
		context = new HashMap<String, Map>();
		properties = new HashMap();
		properties.put("factory", "gearsfactoryclass");
		context.put("properties", properties);
		fname = "gearsgearsclass.fcrec";
		fcontent = FCRecTemplate.template(context);
		fcrecs.put(fname, fcontent);
		
		FileOutputStream fos = new FileOutputStream(target);
		JarOutputStream jos = new JarOutputStream(fos);
		FileInputStream fis = new FileInputStream(src);
		JarInputStream jis = new JarInputStream(fis);
		JarEntry jarEntry;

		while ((jarEntry = jis.getNextJarEntry()) != null) {
			String entryName = jarEntry.getName();
			byte[] buff = new byte[1024];
			int length;
			jos.putNextEntry(jarEntry);
			while ((length = jis.read(buff, 0, buff.length)) != -1) {
				jos.write(buff, 0, length);
			}
			if ("org/eclipse/wst/javascript/ui/internal/common/contentassist/fcs/js1/startclass.fcrec"
					.equals(entryName)) {
				jos.write('\r');
				jos.write('\n');
				jos.write(startapp.getBytes());
			}
		}

		jis.close();
		fis.close();

		for (String filename : fcrecs.keySet()) {
			String filecontent = fcrecs.get(filename);
			JarEntry newEntry = new JarEntry(
					"org/eclipse/wst/javascript/ui/internal/common/contentassist/fcs/js1/"
							+ filename);
			jos.putNextEntry(newEntry);
			jos.write(filecontent.getBytes());
		}
		jos.close();
		fos.close();
	}
	
	private static String[] split(String var){
		String[] ss = var.split(",");
		List<String> sList = new ArrayList<String>();
		for(String s:ss){
			if (s.trim().length() == 0){
				continue;
			}
			sList.add(s.trim());
		}
		ss = new String[sList.size()];
		sList.toArray(ss);
		return ss;
	}

	private static String removeSpace(String str){
		StringBuilder sb = new StringBuilder();
		char[]  chs = str.toCharArray();
		for(char c:chs){
			if (c == '\t'){
				continue;
			}
			if (c == '\r'){
				continue;
			}
			if (c == '\n'){
				continue;
			}
			if (c == ' '){
				continue;
			}
			sb.append(c);
		}
		return sb.toString();
	}
	private static void processMethodMap(Map map,
			Map<String, String> typeVar) {
		if (map == null){
			return;
		}
		
		Map temp = new HashMap(map);
		map.clear();
		for (Object key : temp.keySet()) {
			String type = (String) temp.get(key);
			String stringKey = removeSpace((String)key);
			map.put(stringKey, type);
			
			String var = typeVar.get(type);
			
			if (var != null) {
				String[] vs = split(var);
				map.put(stringKey, "gears" + vs[0] + "class");
			} 
		}
	}
	private static void preprocessMap(Map map,
			Map<String, String> typeVar) {
		if (map == null){
			return;
		}
		for (Object key : map.keySet()) {
			String type = (String) map.get(key);
			if (type.endsWith("class")){
				type = type.substring(0,type.length() - "class".length());
			}
			String var = typeVar.get(type);
			
			if (var != null) {
				String[] vs = split(var);
				map.put(key, "gears" + vs[0] + "class");
			} 
		}
	}
}
